import asyncio
import threading
import http.cookies
import blivedm
import blivedm.models.web as web_models
from utils import format_coin
from danmu_sender import DanmuSenderManager
import aiohttp
from gift_data_manager import GiftDataManager
import heapq  # 用于实现优先队列
import time
import random  # 新增：用于随机选择感谢语模板

class DanmuQueueManager:
    """弹幕发送队列管理器（支持优先级+6秒间隔）"""

    def __init__(self, danmu_manager: DanmuSenderManager, log_callback):
        self.danmu_manager = danmu_manager
        self.log_callback = log_callback
        # 改用优先队列（heapq）：存储格式 (-priority, timestamp, room_id, message)
        # 负号因为heapq是小根堆，负优先级越大越先弹出（高优先级优先）
        self.queue = []
        self.lock = threading.Lock()  # 线程安全锁（多线程操作队列需加锁）
        self.is_running = False
        self.worker_thread = None
        self.last_send_time = 0  # 记录上一条弹幕的发送时间（确保间隔≥6秒）

    def start(self):
        """启动队列工作线程"""
        if self.is_running:
            return

        self.is_running = True
        self.worker_thread = threading.Thread(
            target=self._process_queue,
            daemon=True
        )
        self.worker_thread.start()
        self.log_callback("【弹幕队列】队列管理器已启动")

    def stop(self):
        """停止队列工作线程"""
        self.is_running = False
        if self.worker_thread:
            self.worker_thread.join(timeout=3)  # 延长超时时间，确保线程安全退出
        self.log_callback("【弹幕队列】队列管理器已停止")

    def add_danmu(self, room_id: str, message: str, priority: int = 0):
        """添加弹幕到优先队列（线程安全）"""
        with self.lock:  # 加锁防止多线程同时修改队列
            heapq.heappush(
                self.queue,
                (-priority, time.time(), room_id, message)  # 负优先级实现“高优先级先出”
            )
        self.log_callback(f"【队列添加】优先级{priority} | 内容：{message[:20]}...")

    def _process_queue(self):
        """处理队列中的弹幕（严格6秒间隔+优先级排序）"""
        while self.is_running:
            try:
                # 1. 线程安全获取队列中的高优先级任务
                task = None
                with self.lock:
                    if self.queue:  # 队列非空时弹出高优先级任务
                        task = heapq.heappop(self.queue)
                        # 解析任务：恢复优先级（去掉负号）、入队时间、房间ID、消息
                        priority = -task[0]
                        enqueue_time = task[1]
                        room_id = task[2]
                        message = task[3]

                if not task:  # 队列为空时，短暂休眠避免CPU空转
                    time.sleep(0.1)
                    continue

                # 2. 计算需等待的时间（确保与上一条弹幕间隔≥6秒）
                current_time = time.time()
                required_interval = 6.0  # 固定6秒间隔
                # 两种等待逻辑取最大值：①与上一条的间隔 ②任务入队后至少等待1秒（避免瞬时发送）
                wait_time = max(
                    required_interval - (current_time - self.last_send_time),
                    1.0 - (current_time - enqueue_time)  # 防止任务入队后立即发送（可选）
                )
                wait_time = max(wait_time, 0)  # 确保等待时间非负

                if wait_time > 0:
                    time.sleep(wait_time)

                # 3. 发送弹幕
                try:
                    sender = self.danmu_manager.get_sender(room_id)
                    success, result = sender.send_danmu(message)

                    if success:
                        self.last_send_time = time.time()  # 更新上一条发送时间
                        self.log_callback(
                            f"【队列发送】优先级{priority} | 房间{room_id} | 内容：{message[:20]}..."
                        )
                    else:
                        self.log_callback(
                            f"【队列失败】房间{room_id} | 原因：{result} | 内容：{message[:20]}..."
                        )
                        # 可选：发送失败时重新入队（降低优先级，避免无限重试）
                        self.add_danmu(room_id, message, priority=priority - 1)

                except Exception as e:
                    self.log_callback(f"【队列异常】发送失败：{str(e)} | 内容：{message[:20]}...")
                    # 可选：异常时重新入队（同样降低优先级）
                    self.add_danmu(room_id, message, priority=priority - 1)

            except Exception as e:
                self.log_callback(f"【队列处理异常】{str(e)}")
                time.sleep(1)  # 异常后休眠1秒，避免频繁报错


class GiftListener:
    """礼物监听与盈亏推送类（逻辑不变，适配新队列）"""

    def __init__(self,   config_manager, query_lister_text: str, listen_room_ids: list, push_target_room: str, danmu_manager: DanmuSenderManager, log_callback):
        self.listen_room_ids = [str(rid).strip() for rid in listen_room_ids if rid.strip()]
        self.push_target_room = push_target_room.strip()
        self.danmu_manager = danmu_manager
        self.log_callback = log_callback
        self.is_listening = False
        self.listen_thread = None
        self.session = None
        self.clients = []
        # 初始化新的优先队列管理器
        self.danmu_queue = DanmuQueueManager(danmu_manager, log_callback)
        self.query_lister_text = query_lister_text
        self.config_manager = config_manager

    def _init_aio_session(self) -> bool:
        """初始化aiohttp会话（逻辑不变）"""
        if not self.danmu_manager.cookies.get('SESSDATA'):
            self.log_callback("【监听失败】未登录（需SESSDATA Cookie）")
            return False

        cookies = http.cookies.SimpleCookie()
        SESSDATA = self.danmu_manager.cookies['SESSDATA'].replace(',', '%2C').replace('*', '%2A')
        cookies['SESSDATA'] = SESSDATA
        cookies['SESSDATA']['domain'] = 'bilibili.com'

        self.session = aiohttp.ClientSession()
        self.session.cookie_jar.update_cookies(cookies)
        return True

    async def _listen_client(self, room_id: str) -> None:
        """监听单个房间（逻辑不变）"""
        client = blivedm.BLiveClient(int(room_id), session=self.session)
        handler = GiftHandler(self.config_manager,self.query_lister_text, room_id, self.push_target_room, self.danmu_queue, self.log_callback)
        client.set_handler(handler)
        self.clients.append(client)

        client.start()
        try:
            await client.join()
        finally:
            await client.stop_and_close()

    async def _listen_loop(self) -> None:
        """异步监听循环（逻辑不变）"""
        if not self._init_aio_session():
            return

        try:
            self.danmu_queue.start()  # 启动新队列
            tasks = [self._listen_client(rid) for rid in self.listen_room_ids]
            await asyncio.gather(*tasks)
        except Exception as e:
            self.log_callback(f"【监听异常】{str(e)}")
        finally:
            self.danmu_queue.stop()  # 停止新队列
            if self.session:
                await self.session.close()
            self.log_callback("【监听停止】所有房间监听已关闭")

    def start_listen(self) -> None:
        """启动监听（逻辑不变）"""
        if self.is_listening:
            self.log_callback("【监听提示】已在监听中，无需重复启动")
            return
        if not self.listen_room_ids:
            self.log_callback("【监听失败】请设置要监听的房间ID")
            return
        if not self.push_target_room:
            self.log_callback("【监听失败】请设置推送目标房间ID")
            return

        self.is_listening = True
        self.listen_thread = threading.Thread(
            target=lambda: asyncio.run(self._listen_loop()),
            daemon=True
        )
        self.listen_thread.start()
        self.log_callback(f"【监听启动】监听房间：{', '.join(self.listen_room_ids)}，推送目标：{self.push_target_room}")

    def stop_listen(self) -> None:
        """停止监听（逻辑不变）"""
        if not self.is_listening:
            self.log_callback("【监听提示】未在监听中，无需停止")
            return

        self.is_listening = False
        for client in self.clients:
            client.stop()
        self.clients.clear()
        self.danmu_queue.stop()
        self.log_callback("【监听停止】正在关闭监听（请等待3-5秒）")


class GiftHandler(blivedm.BaseHandler):
    """礼物事件处理器（适配新队列，逻辑微调）"""

    def __init__(self,     config_manager, query_lister_text: str, listen_room_id: str, push_target_room: str, danmu_queue: DanmuQueueManager, log_callback):
        self.listen_room_id = listen_room_id
        self.push_target_room = push_target_room
        self.danmu_queue = danmu_queue
        self.log_callback = log_callback
        self.data_manager = GiftDataManager()
        self.query_lister_text = query_lister_text,
        self.config_manager = config_manager

    def _on_gift(self, client: blivedm.BLiveClient, message: web_models.GiftMessage) -> None:
        """处理盲盒礼物逻辑
        功能：计算盲盒盈亏、记录数据、发送弹幕通知
        """
        # 过滤无效礼物（原价为0的礼物不处理）
        if message.original_gift_price == 0:
            self.log_callback(f"【盲盒过滤】房间{self.listen_room_id} | 过滤无效礼物（原价为0）")
            return

        # 1. 计算盲盒盈亏相关数据
        cost = message.total_coin  # 花费的硬币数
        income = message.combo_total_coin  # 获得的硬币数
        profit = income - cost  # 盈亏金额
        profit_ratio = (profit / cost * 100) if cost > 0 else 0  # 盈亏比例（百分比）

        # 确定盈亏状态和显示颜色
        if profit > 0:
            profit_status, profit_color = "赚了", "🟢"
        elif profit < 0:
            profit_status, profit_color = "亏了", "🔴"
        else:
            profit_status, profit_color = "持平", "🟡"

        # 确定盈亏等级（根据比例划分）
        if abs(profit_ratio) >= 100:
            profit_level = "🎉血赚/血亏🎉"
        elif abs(profit_ratio) >= 50:
            profit_level = "🔥大赚/大亏🔥"
        elif abs(profit_ratio) >= 20:
            profit_level = "⭐小赚/小亏⭐"
        else:
            profit_level = "➖微赚/微亏➖"

        # 格式化硬币显示（如转换为"1000金豆"、"50电池"等）
        cost_str = format_coin(cost, message.coin_type)
        income_str = format_coin(income, message.coin_type)
        profit_str = format_coin(abs(profit), message.coin_type)

        # 2. 输出盲盒详情日志
        log_msg = (
            f"【盲盒监听】房间{self.listen_room_id} | {message.uname}({message.uid}) | "
            f"投喂{message.original_gift_name}x{message.gift_num} → 爆出{message.gift_name}x{message.gift_num} | "
            f"花费{cost_str} | 收入{income_str} | {profit_color}{profit_status}{profit_str}({profit_ratio:+.1f}%) | {profit_level}"
        )
        self.log_callback(log_msg)

        # 3. 存储盲盒数据到数据管理器
        gift_record = {
            "uid": message.uid, "uname": message.uname, "listen_room_id": self.listen_room_id,
            "original_gift_name": message.original_gift_name, "original_gift_num": message.gift_num,
            "result_gift_name": message.gift_name, "result_gift_num": message.gift_num,
            "cost": cost, "income": income, "profit": profit, "profit_ratio": profit_ratio,
            "coin_type": message.coin_type
        }
        self.data_manager.add_record(gift_record)
        self.log_callback(f"【数据存储】已记录盲盒数据: {message.uname}({message.uid}) | 记录内容: {gift_record}")

        # 4. 添加盲盒结果到弹幕队列（赚了优先级高，亏了优先级低）
        if not self.push_target_room:
            self.log_callback(f"【弹幕队列】未设置目标房间，跳过发送盲盒结果")
            return

        danmu_msg = f"{message.uname} 一个{message.original_gift_name}{profit_status}{profit_str}"
        priority = 1 if profit > 0 else 0  # 赚了优先发送
        self.danmu_queue.add_danmu(self.push_target_room, danmu_msg, priority)
        self.log_callback(
            f"【弹幕队列】已添加盲盒结果弹幕 | 房间{self.push_target_room} | 内容: {danmu_msg} | 优先级: {priority}")

    def _on_danmaku(self, client: blivedm.BLiveClient, message: web_models.DanmakuMessage):
        """处理用户弹幕消息
        功能：1. 响应查询指令 2. 处理关键词回复
        """
        self.log_callback(f"【弹幕接收】房间{client.room_id} | {message.uname}({message.uid}) | 内容: {message.msg}")

        # 1. 处理查询弹幕（用户发送指定查询指令时）
        if self.query_lister_text == message.msg:
            self.log_callback(f"【查询处理】检测到查询指令 | 用户: {message.uname}({message.uid})")
            # 获取用户本月数据统计
            total_data = self.data_manager.get_total_month_stats(uid=str(message.uid))
            # 发送查询结果到弹幕队列
            query_msg = f"{message.uname} 本月记录总数:{total_data['记录总数']} 总盈亏:{round(total_data['总盈亏(gold)'] / 1000, 1)}"
            self.danmu_queue.add_danmu(self.push_target_room, query_msg, priority=1)
            self.log_callback(f"【查询回复】已发送查询结果 | 内容: {query_msg} | 房间{self.push_target_room}")

        # 2. 处理关键词弹幕（匹配预设关键词并回复）
        if self.config_manager.comprehensive_settings['keyword_responses']['enabled']:
            self.log_callback(f"【关键词处理】开始检测关键词 | 用户: {message.uname} | 弹幕: {message.msg}")
            # 获取关键词-回复映射字典（配置中定义）
            keyword_map = self.config_manager.comprehensive_settings['keyword_responses'].get('list_of_scripts', {})

            # 检查配置有效性和弹幕内容
            if not keyword_map:
                self.log_callback(f"【关键词处理】配置为空，跳过检测")
                return
            if not hasattr(message, 'msg') or not message.msg:
                self.log_callback(f"【关键词处理】弹幕内容为空，跳过检测")
                return

            # 遍历关键词，检测是否匹配
            matched = False
            for keyword, response in keyword_map.items():
                if keyword in message.msg:  # 子串匹配（包含关键词即触发）
                    # 发送匹配到的回复
                    self.danmu_queue.add_danmu(
                        self.push_target_room,
                        response,
                        priority=1
                    )
                    self.log_callback(
                        f"【关键词回复】匹配成功 | 关键词: {keyword} | 回复: {response} | 房间{self.push_target_room}")
                    matched = True
                    break  # 只触发第一个匹配的关键词

            if not matched:
                self.log_callback(f"【关键词处理】未匹配到任何关键词 | 弹幕: {message.msg}")

    def _on_interact_word(self, client: blivedm.BLiveClient, message: web_models.InteractWordMessage):
        """处理用户互动消息
        功能：1. 欢迎用户进入直播间 2. 感谢用户关注直播间
        """
        self.log_callback(
            f"【互动事件】用户{message.username}({message.uid}) | 事件类型: {message.msg_type} | 房间{client.room_id}")

        # 1. 处理用户进入直播间（msg_type=1）
        if message.msg_type == 1:
            self.log_callback(f"【进入事件】用户{message.username}进入房间{client.room_id}")
            # 检查是否开启欢迎消息功能
            if self.config_manager.comprehensive_settings['welcome_message']['enabled']:
                self.log_callback(f"【欢迎消息】开始处理欢迎逻辑 | 用户: {message.username}")
                # 获取欢迎语模板列表（配置中定义）
                welcome_templates = self.config_manager.comprehensive_settings['welcome_message'].get('list_of_scripts',
                                                                                                      [])

                # 处理模板为空的情况（使用默认模板）
                if not welcome_templates:
                    self.log_callback(f"【欢迎消息】模板列表为空，使用默认模板")
                    welcome_content = f'欢迎{message.username}进入直播间～新进来的朋友点点关注，点亮灯牌不迷路哦～'
                else:
                    # 随机选择一个模板并替换用户名参数
                    selected_template = random.choice(welcome_templates)
                    welcome_content = selected_template.format(username=message.username)
                    self.log_callback(f"【欢迎消息】已选择模板 | 模板: {selected_template} | 替换后: {welcome_content}")

                # 发送欢迎消息到弹幕队列
                self.danmu_queue.add_danmu(
                    self.push_target_room,
                    welcome_content,
                    priority=1
                )
                self.log_callback(f"【欢迎消息】已发送 | 房间{self.push_target_room} | 内容: {welcome_content}")
            else:
                self.log_callback(f"【欢迎消息】功能未开启，跳过处理")

        # 2. 处理用户关注直播间（msg_type=2）
        if message.msg_type == 2:
            self.log_callback(f"【关注事件】用户{message.username}关注了房间{client.room_id}")
            # 检查是否开启关注感谢功能
            if self.config_manager.comprehensive_settings['thank_for_follow']['enabled']:
                self.log_callback(f"【关注感谢】开始处理感谢逻辑 | 用户: {message.username}")
                # 获取感谢语模板列表（配置中定义）
                thank_templates = self.config_manager.comprehensive_settings['thank_for_follow'].get('list_of_scripts',
                                                                                                     [])

                # 处理模板为空的情况（使用默认模板）
                if not thank_templates:
                    self.log_callback(f"【关注感谢】模板列表为空，使用默认模板")
                    thank_content = f'感谢{message.username}的关注！记得常来直播间互动哦～'
                else:
                    # 随机选择一个模板并替换用户名参数
                    selected_template = random.choice(thank_templates)
                    thank_content = selected_template.format(username=message.username)
                    self.log_callback(f"【关注感谢】已选择模板 | 模板: {selected_template} | 替换后: {thank_content}")

                # 发送感谢消息到弹幕队列
                self.danmu_queue.add_danmu(
                    self.push_target_room,
                    thank_content,
                    priority=1
                )
                self.log_callback(f"【关注感谢】已发送 | 房间{self.push_target_room} | 内容: {thank_content}")
            else:
                self.log_callback(f"【关注感谢】功能未开启，跳过处理")
